
#include "core/api/core_api.h"
#include "core/service.h"
#include "core/timer.h"
#include "core/dest_cache.h"
#include "error.h"

extern "C" {

#define ENSURE_PARAM(pred) if (!(pred)) return core_error::invalid_parameters;
#define EXEC_BEGIN try{
#define EXEC_CATCH_ERROR }catch(error_exception& e){return e.code().value();}

void debug_log(const char* log) {
  DLOG(INFO) << log;
}

void* core_service_context(void* service) {
  if (!service) return NULL;
  return static_cast<Service*>(service)->context();
}

uint32_t core_callback(void* service, msg_handler h) {
  ENSURE_PARAM(service);
  Service* service_ptr = static_cast<Service*>(service);
  service_ptr->SetMsgHandler(h);
  return 0;
}

uint32_t core_send_by_handle(uint32_t destination, const CoreMessage* msg) {
  ENSURE_PARAM(msg);
  EXEC_BEGIN
    Services::Instance().Send(Handle(destination), *msg);
  EXEC_CATCH_ERROR
  return 0;
}

uint32_t core_send_by_name(const char* destination, const CoreMessage* msg) {
  ENSURE_PARAM(msg);
  EXEC_BEGIN
    Services::Instance().Send(destination, *msg);
  EXEC_CATCH_ERROR
  return 0;
}

uint32_t add_timer(void* service, uint32_t trigger_count, uint32_t duration_ms,
                   void* user_data, timer_callback timer_cb) {
  if (!service) return -1;
  Service* service_ptr = static_cast<Service*>(service);
  return Timers::Instance().Add(*service_ptr, 
                                trigger_count,
                                utils::milliseconds(duration_ms),
                                user_data,
                                reinterpret_cast<uintptr_t>(timer_cb)); 
}

void core_update_dest_record(const char* raw_list) {
  DestCache::Instance().UpdateRecord(raw_list);
}

void core_update_dest_record_1(uint16_t is_add, 
                               const char* key,
                               const char* val) {
  DestCache::Instance().UpdateRecord(is_add, key, val);
}

uint32_t core_launch_service(const char* name,
                             const char* module_name,
                             const char* args,
                             uint32_t* handle) {
  ENSURE_PARAM(module_name);
  ENSURE_PARAM(handle);
  EXEC_BEGIN
    Handle h = Services::Instance().New(name, module_name, args);
    *handle = h.value();
    return 0;
  EXEC_CATCH_ERROR
}

#undef ENSURE_PARAM
#undef EXEC_BEGIN
#undef EXEC_CATCH_ERROR

}

